#ifndef __M_ROOM_H__
#define __M_ROOM_H__

#include "util.hpp"
#include "logger.hpp"
#include "online.hpp"
#include "db.hpp"

// 前向声明 room 类，用于解决循环依赖问题
class room;

// 定义智能指针类型，方便管理room对象生命周期
using room_ptr = std::shared_ptr<room>;

// 定义棋盘的行数和列数（15x15的棋盘）
#define BOARD_ROW 15
#define BOARD_COL 15
// 定义棋子颜色常量：白色棋子为1，黑色棋子为2
#define CHESS_WHITE 1
#define CHESS_BLACK 2
// 定义房间状态枚举：游戏开始和游戏结束两种状态
typedef enum { GAME_START, GAME_OVER } room_statu;

/**
 * @brief 游戏房间类，管理五子棋对局的所有逻辑
 */
class room {
private:
    uint64_t _room_id;                // 房间唯一ID
    room_statu _statu;                // 房间当前状态
    int _player_count;                // 房间内玩家数量
    uint64_t _white_id;               // 白棋玩家ID
    uint64_t _black_id;               // 黑棋玩家ID
    user_table* _tb_user;             // 用户数据表操作指针
    online_manager* _online_user;     // 在线用户管理指针
    std::vector<std::vector<int>> _board;  // 15x15的棋盘，0表示空，1表示白棋，2表示黑棋

private:
    /**
     * @brief 检查是否五子连珠
     * @param row 当前落子的行坐标
     * @param col 当前落子的列坐标
     * @param row_off 行方向偏移量（-1,0,1）
     * @param col_off 列方向偏移量（-1,0,1）
     * @param color 棋子颜色
     * @return 如果五子连珠返回true，否则false
     */
    bool five(int row, int col, int row_off, int col_off, int color) {
        int count = 1;  // 当前棋子本身计数为1
        
        // 向正方向检查相同颜色的棋子
        int search_row = row + row_off;
        int search_col = col + col_off;
        while (search_row >= 0 && search_row < BOARD_ROW &&
               search_col >= 0 && search_col < BOARD_COL &&
               _board[search_row][search_col] == color) {
            count++;
            search_row += row_off;
            search_col += col_off;
        }
        
        // 向反方向检查相同颜色的棋子
        search_row = row - row_off;
        search_col = col - col_off;
        while (search_row >= 0 && search_row < BOARD_ROW &&
               search_col >= 0 && search_col < BOARD_COL &&
               _board[search_row][search_col] == color) {
            count++;
            search_row -= row_off;
            search_col -= col_off;
        }
        
        // 如果同色棋子数大于等于5，则返回true
        return (count >= 5);
    }
    
    /**
     * @brief 检查当前落子是否获胜
     * @param row 行坐标
     * @param col 列坐标
     * @param color 棋子颜色
     * @return 如果获胜返回获胜玩家ID，否则返回0
     */
    uint64_t check_win(int row, int col, int color) {
        // 检查四个方向是否有五子连珠
        if (five(row, col, 0, 1, color) ||   // 水平方向
            five(row, col, 1, 0, color) ||    // 垂直方向
            five(row, col, -1, 1, color) ||  // 左上到右下
            five(row, col, -1, -1, color)) {  // 右上到左下
            return color == CHESS_WHITE ? _white_id : _black_id;
        }
        return 0;
    }

public:
    /**
     * @brief 构造函数
     * @param room_id 房间ID
     * @param tb_user 用户数据表指针
     * @param online_user 在线用户管理指针
     */
    room(uint64_t room_id, user_table* tb_user, online_manager* online_user)
        :_room_id(room_id), _statu(GAME_START), _player_count(0), 
         _tb_user(tb_user), _online_user(online_user), 
         _board(BOARD_ROW, std::vector<int>(BOARD_COL, 0)) {
        DLOG("%lu 房间创建成功！！", _room_id);
    }

    /**
     * @brief 析构函数
     */
    ~room() {
        DLOG("%lu 房间销毁成功！！", _room_id);
    }

    // 以下是各种getter和setter方法

    uint64_t id() { return _room_id; }
    room_statu statu() { return _statu; }
    int player_count() { return _player_count; }
    void add_white_user(uint64_t uid) { _white_id = uid; _player_count++; }
    void add_black_user(uint64_t uid) { _black_id = uid; _player_count++; }
    uint64_t get_white_user() { return _white_id; }
    uint64_t get_black_user() { return _black_id; }

    /**
     * @brief 处理下棋请求
     * @param req 请求的JSON数据
     * @return 响应的JSON数据
     */
    Json::Value handle_chess(Json::Value& req) {
        Json::Value json_resp = req;
        
        // 检查白棋玩家是否在线
        if (!_online_user->is_in_game_room(_white_id)) {
            json_resp["result"] = true;
            json_resp["reason"] = "对方掉线，不战而胜！";
            json_resp["winner"] = (Json::UInt64)_black_id;
            return json_resp;
        }
        // 检查黑棋玩家是否在线
        if (!_online_user->is_in_game_room(_black_id)) {
            json_resp["result"] = true;
            json_resp["reason"] = "对方掉线，不战而胜！";
            json_resp["winner"] = (Json::UInt64)_white_id;
            return json_resp;
        }

        // 获取落子位置和当前玩家ID
        int chess_row = req["row"].asInt();
        int chess_col = req["col"].asInt();
        uint64_t cur_uid = req["uid"].asUInt64();

        // 检查该位置是否已有棋子
        if (_board[chess_row][chess_col] != 0) {
            json_resp["result"] = false;
            json_resp["reason"] = "当前位置已有棋子！";
            return json_resp;
        }

        // 根据玩家ID确定棋子颜色
        int cur_color = (cur_uid == _white_id) ? CHESS_WHITE : CHESS_BLACK;
        _board[chess_row][chess_col] = cur_color;
        
        // 检查是否获胜
        uint64_t winner_id = check_win(chess_row, chess_col, cur_color);
        if (winner_id != 0) {
            json_resp["reason"] = "五星连珠，战无敌！";
        }
        
        json_resp["result"] = true;
        json_resp["winner"] = (Json::UInt64)winner_id;
        return json_resp;
    }

    /**
     * @brief 处理聊天请求
     * @param req 请求的JSON数据
     * @return 响应的JSON数据
     */
    Json::Value handle_chat(Json::Value& req) {
        Json::Value json_resp = req;
        std::string msg = req["message"].asString();
        uint64_t sender_uid = req["uid"].asUInt64();

        // 敏感词检测（示例）
        if (msg.find("垃圾") != std::string::npos || 
            msg.find("sb") != std::string::npos) {
            json_resp["result"] = false;
            json_resp["reason"] = "消息包含敏感词！";
            send_to_user(sender_uid, json_resp);  // 只发给发送者
            return json_resp;
        }

        // 正常消息广播给房间内所有玩家
        json_resp["result"] = true;
        broadcast(json_resp);
        return json_resp;
    }

    /**
     * @brief 处理玩家退出房间
     * @param uid 退出玩家的ID
     * @return 响应的JSON数据
     */
    Json::Value handle_exit(uint64_t uid) {
        Json::Value json_resp;
        if (_statu == GAME_START) {
            // 确定获胜者
            uint64_t winner_id = (uid == _white_id) ? _black_id : _white_id;
            json_resp["optype"] = "put_chess";
            json_resp["result"] = true;
            json_resp["reason"] = "对方掉线，不战而胜！";
            json_resp["room_id"] = (Json::UInt64)_room_id;
            json_resp["uid"] = (Json::UInt64)uid;
            json_resp["row"] = -1;
            json_resp["col"] = -1;
            json_resp["winner"] = (Json::UInt64)winner_id;
            
            // 更新数据库中的胜负记录
            uint64_t loser_id = (winner_id == _white_id) ? _black_id : _white_id;
            _tb_user->win(winner_id);
            _tb_user->lose(loser_id);
            _statu = GAME_OVER;
            broadcast(json_resp);
        }
        _player_count--;
        return json_resp;
    }

    /**
     * @brief 向指定用户发送消息
     * @param uid 目标用户ID
     * @param rsp 要发送的JSON响应
     */
    void send_to_user(uint64_t uid, Json::Value& rsp) {
        std::string body;
        json_util::serialize(rsp, body);
        wsserver_t::connection_ptr conn = _online_user->get_conn_from_room(uid);
        if (conn) {
            conn->send(body);
        } else {
            DLOG("玩家 %lu 连接不存在", uid);
        }
    }

    /**
     * @brief 广播消息给房间内所有玩家
     * @param rsp 要广播的JSON响应
     * @param target_uid 如果指定则只发给该用户，否则广播给所有人
     */
    void broadcast(Json::Value& rsp, uint64_t target_uid = 0) {
        if (target_uid != 0) {
            send_to_user(target_uid, rsp);
            return;
        }

        std::string body;
        json_util::serialize(rsp, body);

        // 发送给白棋玩家
        if (_white_id != 0) {
            send_to_user(_white_id, rsp);
        }
        // 发送给黑棋玩家
        if (_black_id != 0) {
            send_to_user(_black_id, rsp);
        }
    }

    /**
     * @brief 请求处理入口
     * @param req 请求的JSON数据
     */
    void handle_request(Json::Value& req) {
        Json::Value json_resp;
        uint64_t room_id = req["room_id"].asUInt64();
        
        // 检查房间ID是否匹配
        if (room_id != _room_id) {
            json_resp["optype"] = req["optype"].asString();
            json_resp["result"] = false;
            json_resp["reason"] = "房间号不匹配！";
            broadcast(json_resp);
            return;
        }

        // 根据操作类型分发处理
        std::string optype = req["optype"].asString();
        if (optype == "put_chess") {
            json_resp = handle_chess(req);
            if (json_resp["winner"].asUInt64() != 0) {
                // 如果有玩家获胜，更新数据库
                uint64_t winner_id = json_resp["winner"].asUInt64();
                uint64_t loser_id = (winner_id == _white_id) ? _black_id : _white_id;
                _tb_user->win(winner_id);
                _tb_user->lose(loser_id);
                _statu = GAME_OVER;
            }
            broadcast(json_resp);
        }
        else if (optype == "chat") {
            handle_chat(req);  // 内部已处理发送
        }
        else {
            json_resp["optype"] = optype;
            json_resp["result"] = false;
            json_resp["reason"] = "未知请求类型";
            broadcast(json_resp);
        }
    }
};

/**
 * @brief 房间管理类，负责创建、查找和删除房间
 */
class room_manager {
private:
    uint64_t _next_rid;                             // 下一个房间ID
    std::mutex _mutex;                              // 互斥锁，保证线程安全
    user_table* _tb_user;                           // 用户数据表指针
    online_manager* _online_user;                   // 在线用户管理指针
    std::unordered_map<uint64_t, room_ptr> _rooms;  // 房间ID到房间对象的映射
    std::unordered_map<uint64_t, uint64_t> _users;  // 用户ID到房间ID的映射

public:
    /**
     * @brief 构造函数
     * @param ut 用户数据表指针
     * @param om 在线用户管理指针
     */
    room_manager(user_table* ut, online_manager* om)
        :_next_rid(1), _tb_user(ut), _online_user(om) {
        DLOG("房间管理器初始化完成");
    }

    /**
     * @brief 析构函数
     */
    ~room_manager() {
        DLOG("房间管理器销毁");
    }

    /**
     * @brief 创建新房间
     * @param uid1 玩家1的ID
     * @param uid2 玩家2的ID
     * @return 创建的房间指针，失败返回nullptr
     */
    room_ptr create_room(uint64_t uid1, uint64_t uid2) {
        // 检查玩家是否在大厅
        if (!_online_user->is_in_game_hall(uid1)) {
            DLOG("玩家 %lu 不在大厅", uid1);
            return nullptr;
        }
        if (!_online_user->is_in_game_hall(uid2)) {
            DLOG("玩家 %lu 不在大厅", uid2);
            return nullptr;
        }

        std::unique_lock<std::mutex> lock(_mutex);
        // 创建新房间
        room_ptr rp(new room(_next_rid, _tb_user, _online_user));
        rp->add_white_user(uid1);
        rp->add_black_user(uid2);
        
        // 更新映射关系
        _rooms[_next_rid] = rp;
        _users[uid1] = _next_rid;
        _users[uid2] = _next_rid;
        _next_rid++;
        
        return rp;
    }

    /**
     * @brief 通过房间ID获取房间
     * @param rid 房间ID
     * @return 房间指针，不存在返回nullptr
     */
    room_ptr get_room_by_rid(uint64_t rid) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _rooms.find(rid);
        return (it != _rooms.end()) ? it->second : nullptr;
    }

    /**
     * @brief 通过用户ID获取房间
     * @param uid 用户ID
     * @return 房间指针，不存在返回nullptr
     */
    room_ptr get_room_by_uid(uint64_t uid) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto uit = _users.find(uid);
        if (uit == _users.end()) return nullptr;
        
        auto rit = _rooms.find(uit->second);
        return (rit != _rooms.end()) ? rit->second : nullptr;
    }

    /**
     * @brief 移除指定房间
     * @param rid 要移除的房间ID
     */
    void remove_room(uint64_t rid) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _rooms.find(rid);
        if (it == _rooms.end()) return;

        room_ptr rp = it->second;
        // 移除用户映射
        _users.erase(rp->get_white_user());
        _users.erase(rp->get_black_user());
        // 移除房间
        _rooms.erase(rid);
    }

    /**
     * @brief 移除房间中的用户
     * @param uid 要移除的用户ID
     */
    void remove_room_user(uint64_t uid) {
        room_ptr rp = get_room_by_uid(uid);
        if (!rp) return;

        // 处理玩家退出逻辑
        rp->handle_exit(uid);
        // 如果房间没有玩家了，则移除房间
        if (rp->player_count() == 0) {
            remove_room(rp->id());
        }
    }
};

#endif